//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2003-2007
// Holux is registered trademark of Holux Technology Inc.
//
// Holux WPO waypoints export.
//

# include "StdAfx.h"
# include "HoluxWpo.h"
# include "Save.h"
# include "Map.h"
# include "Status.h"
# include "SaveFileDlg.h"
# include "FileWriter.h"
# include "fast_floor.h"
# include "Globals.h"

class CHoluxWpoExport : public CMapSaver {
  public:
	virtual bool CanSave (const map_t & _map) {return true;}

	virtual bool Save (HANDLE _hFile, const char * _strFileName, const map_t & _map) {
		return _Save (_hFile, _strFileName, "Holux MapShow waypoints (*.wpo)\0*.wpo\0", _map);
	}

  private:
	bool _Save (HANDLE _hFile, const map_t & _map);
	bool _Save (HANDLE _hFile, const char * _strFileName, const char * _strFilter, const map_t & _map);
};

DECLARE_WPTRK_EXPORT (CHoluxWpoExport, "holux-wpo", "wpo", "Holux MapShow waypoints (*.wpo)");

bool CHoluxWpoExport::_Save (HANDLE _hFile, const char * _strFileName, const char * _strFilter, const map_t & _map) {
	if (_hFile) {
		return _Save (_hFile, _map);
	} else {
		//
		// Prepare default file name.
		//
		char strFileName [MAX_PATH + 1];
		::strncpy (strFileName, _strFileName, MAX_PATH);
		strFileName [MAX_PATH] = '\0';
		if (! SaveFileDlg ("wpo", _strFilter, strFileName))
			return false;

		//
		// Open the file.
		//
		const CFileForWrite hFile (strFileName);
		if (! hFile.IsValid ()) {
			ErrorMsgBox ("Can't create file:\n %s", strFileName);
			return false;
		}

		return _Save (hFile, _map);
	}
}

bool CHoluxWpoExport::_Save (HANDLE _hFile, const map_t & _map) {
	// Get time zone shift.
	TIME_ZONE_INFORMATION tzi;
	if (::GetTimeZoneInformation (& tzi) == TIME_ZONE_ID_DAYLIGHT)
		tzi.Bias += tzi.DaylightBias;
	const double dtTimeShift = float (tzi.Bias)/(24*60);

	SYSTEMTIME stCurrentTime;
	::GetLocalTime (& stCurrentTime);

	typedef std::map<const rgn_t *, size_t> wpt2idx_t;
	wpt2idx_t wpt2idx;

	SetProgressStatus (0);

	//
	// Prepare the file content.
	//
	CWpoFile wpo;
	::memset (& wpo, 0, sizeof (wpo));

	// Prepare waypoints header.
	wpo.WptHdr.dwSignature = c_dwWpoWptSignature;
	::memset (& wpo.WptHdr.wIdx, 0xFF, sizeof (wpo.WptHdr.wIdx));

	size_t cOrdinal = 0;

	size_t cPoint = 0;
	const layer_t & layer_points = _map.layers [rkPoint];
	const rgns_t & points = layer_points.rgns;
	const size_t cPoints = layer_points.cRgns;
	rgns_t::const_iterator iRgn;
	for (iRgn = points.begin (); iRgn != points.end (); ++ iRgn, ++ cPoint) {
		const rgn_t & rgn = * iRgn;
		if (rgn.IsDeleted () || ! rgn.IsWaypoint ())
			continue;

		const waypoint_info_t * const pWptExtra = rgn.pExtra ? rgn.pExtra->wtr.wpt () : NULL;

		// Save waypoint.
		for (size_t cOrigin = 0; cOrigin < rgn.origins.size (); ++ cOrigin) {
			const rgn_origin_t & origin = rgn.origins [cOrigin];
			if (origin.bDeleted)
				continue;

			if (cOrdinal >= c_cWpoMaxWaypoints)
				break;
			CWpoWaypoint & wpt = wpo.Waypoints [cOrdinal];

			// Name.
			::memset (& wpt.strName, ' ', sizeof (wpt.strName));
			::strncpy (wpt.strName,    rgn.strLabel.c_str (),   rgn.strLabel.size ()   < sizeof (wpt.strName)    ? rgn.strLabel.size   () : sizeof (wpt.strName));

			// Comment.
			::memset (& wpt.strComment, ' ', sizeof (wpt.strComment));
			::strncpy (wpt.strComment, rgn.strComment.c_str (), rgn.strComment.size () < sizeof (wpt.strComment) ? rgn.strComment.size () : sizeof (wpt.strComment));

			// Position.
			wpt.lX =  fast_floor (origin.point.x*36000 + .5f);
			wpt.lY = -fast_floor (origin.point.y*36000 + .5f);

			// Date and time.
			SYSTEMTIME st;
			if (pWptExtra && (pWptExtra->wFlags & waypoint_info_t::defTime))
				::VariantTimeToSystemTime (pWptExtra->dtTime - dtTimeShift, & st);
			else
				st = stCurrentTime;
			wpt.dwDate = st.wDay + (st.wMonth << 8) + (st.wYear << 16);
			wpt.dwTime = st.wSecond + st.wMinute*60 + st.wHour*60*60;

			// Show.
			wpt.btActive = pWptExtra && pWptExtra->GetShow () != waypoint_info_t::showHide ? 1 : 0;

			wpt.wRoutesRefs = 0;

			wpo.WptHdr.btUsed [cOrdinal] = 0xFF;
			wpo.WptHdr.wIdx   [cOrdinal] = cOrdinal;

			wpt2idx [& rgn] = cOrdinal;

			++ cOrdinal;
		}

		SetProgressStatus (fast_floor (30.f*cPoint/cPoints + .5f));
	}

	wpo.WptHdr.wCurrentWaypoints = __min (cOrdinal, c_cWpoMaxWaypoints);
	wpo.WptHdr.wNextWaypoints = wpo.WptHdr.wCurrentWaypoints + 1;

	if (cOrdinal >= c_cWpoMaxWaypoints)
		WarningMsgBox ("Only first 500 waypoints are saved.\n(NOTE:this is the WPO format limitation).");

	//
	// Prepare header of routes.
	//
	::memset (& wpo.RoutesHdr, 0, sizeof (wpo.RoutesHdr));
	wpo.RoutesHdr.dwSignature = c_dwWpoRoutesSignature;
	wpo.RoutesHdr.wNextRoutes = 1;
	::memset (& wpo.RoutesHdr.wIdx, 0xFF, sizeof (wpo.RoutesHdr.wIdx));
	wpo.RoutesHdr.wNavigationRoute = 0xFFFF;
	wpo.RoutesHdr.wReserved = 0;

	::memset (& wpo.btUnused, 0x00, sizeof (wpo.btUnused));

	cOrdinal = 0;

	size_t cPolyline = 0;
	const layer_t & layer_polylines = _map.layers [rkPolyline];
	const rgns_t & polylines = layer_polylines.rgns;
	const size_t cPolylines = layer_polylines.cRgns;
	for (iRgn = polylines.begin (); iRgn != polylines.end (); ++ iRgn, ++ cPolyline) {
		const rgn_t & rgn = * iRgn;
		if (rgn.IsDeleted () || ! rgn.IsRoute ())
			continue;

		if (rgn.pExtra == NULL)
			continue;
		const route_info_t * const pRtExtra = rgn.pExtra->wtr.route ();
		const routepoints_t & rpoints = pRtExtra->points;
		const size_t cRoutePoints = rpoints.size ();

		// Save route.
		if (rgn.elements.size () > 0) {
			const rgn_element_t & element = rgn.elements [0];
			if (element.bDeleted)
				continue;

			if (cOrdinal >= c_cWpoMaxRoutes)
				break;
			CWpoRoute & rt = wpo.Routes [cOrdinal];

			// Name.
			::memset (& rt.strName,    ' ', sizeof (rt.strName));
			::strncpy (rt.strName,    rgn.strLabel.c_str (),   rgn.strLabel.size ()   < sizeof (rt.strName)    ? rgn.strLabel.size   () : sizeof (rt.strName));

			// Comment.
			::memset (& rt.strComment, ' ', sizeof (rt.strComment));
			::strncpy (rt.strComment, rgn.strComment.c_str (), rgn.strComment.size () < sizeof (rt.strComment) ? rgn.strComment.size () : sizeof (rt.strComment));

			// Date and time.
			SYSTEMTIME st;
			if (pRtExtra->wFlags & route_info_t::defTime)
				::VariantTimeToSystemTime (pRtExtra->dtTime - dtTimeShift, & st);
			else
				st = stCurrentTime;
			rt.dwDate = st.wDay + (st.wMonth << 8) + (st.wYear << 16);
			rt.dwTime = st.wSecond + st.wMinute*60 + st.wHour*60*60;

			// Points.
			rt.wWaypoints = 0;
			for (size_t cRoutePoint = 0; cRoutePoint < cRoutePoints; ++ cRoutePoint) {
				if (rt.wWaypoints > c_cWpoMaxWaypointsInRoute)
					break;

				const routepoint_info_t & rpoint = rpoints [cRoutePoint];
				if (rpoint.pWaypoint) {
					const size_t cWptIdx = wpt2idx [rpoint.pWaypoint];
					rt.wWptIdx [rt.wWaypoints] = cWptIdx;

					++ wpo.Waypoints [cWptIdx].wRoutesRefs;
					++ rt.wWaypoints;
				}
			}

			wpo.RoutesHdr.btUsed [cOrdinal] = 0xFF;
			wpo.RoutesHdr.wIdx   [cOrdinal] = cOrdinal;

			++ cOrdinal;
		}

		SetProgressStatus (30 + fast_floor (70.f*cPolyline/cPolylines + .5f));
	}

	wpo.RoutesHdr.wCurrentRoutes = __min (cOrdinal, c_cWpoMaxRoutes);
	wpo.RoutesHdr.wNextRoutes = wpo.RoutesHdr.wCurrentRoutes + 1;

	if (cOrdinal >= c_cWpoMaxRoutes)
		WarningMsgBox ("Only first 30 routes are saved.\n(NOTE:this is the WPO format limitation).");

	//
	// Write the file.
	//
	CFileWriter fw (_hFile);
	fw.WriteBin (wpo);
	fw.FlushBuffer ();

	SetProgressStatus (100);

	return true;
}
